package cn.juque.jdfsystem.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.juque.common.base.PageInfo;
import cn.juque.common.exception.AppException;
import cn.juque.jdfsystem.cache.ConfigInfoCache;
import cn.juque.jdfsystem.entity.RegisterInfo;
import cn.juque.jdfsystem.enums.ConfigCodeEnum;
import cn.juque.jdfsystem.enums.JdfSystemMsgEnum;
import cn.juque.jdfsystem.enums.RegisterExecuteStatusEnum;
import cn.juque.jdfsystem.service.IRegisterInfoService;
import cn.juque.lucenecandy.cache.IpCache;
import cn.juque.lucenecandy.core.base.DeleteByIdsWrapperBuilder;
import cn.juque.lucenecandy.core.base.IdsQueryWrapperBuilder;
import cn.juque.lucenecandy.core.base.QueryWrapperBuilder;
import cn.juque.lucenecandy.core.constants.StrConstant;
import cn.juque.lucenecandy.core.enums.MatchTypeEnum;
import cn.juque.lucenecandy.helper.IndexHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.SortField;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author JUQUE
 * @version 1.0.0
 * <ul>
 *  <li>simple-generator</li>
 *  <li>注册信息</li>
 * </ul>
 * @date 2023-01-10 19:01:26
 **/
@Slf4j
@Service("registerInfoService")
public class RegisterInfoServiceImpl implements IRegisterInfoService {

    @Resource
    private IndexHelper indexHelper;

    @Resource
    private IpCache ipCache;

    @Resource
    private ConfigInfoCache configInfoCache;

    /**
     * 分页查询
     *
     * @param pageInfo     pageInfo
     * @param registerInfo registerInfo
     * @return DataGrid
     */
    @Override
    public List<RegisterInfo> listInfoWithPage(PageInfo pageInfo, RegisterInfo registerInfo) {
        QueryWrapperBuilder<RegisterInfo> queryWrapperBuilder = this.buildQuery(registerInfo);
        queryWrapperBuilder.pageInfo(pageInfo).addSort(RegisterInfo::getIp, SortField.Type.DOC, false);
        return this.indexHelper.searchByPage(queryWrapperBuilder.build());
    }

    /**
     * 查询
     *
     * @param registerInfo registerInfo
     * @return List
     */
    @Override
    public List<RegisterInfo> listInfoWithoutPage(RegisterInfo registerInfo) {
        QueryWrapperBuilder<RegisterInfo> queryWrapperBuilder = this.buildQuery(registerInfo);
        queryWrapperBuilder.addSort(RegisterInfo::getIp, SortField.Type.DOC, false);
        return this.indexHelper.search(queryWrapperBuilder.build());
    }

    /**
     * 保存
     *
     * @param registerInfo registerInfo
     */
    @Override
    public void saveInfo(RegisterInfo registerInfo) {
        registerInfo.setExecuteStatus(RegisterExecuteStatusEnum.DOWN_LINE.getCode());
        this.indexHelper.addDocument(registerInfo);
        this.sync();
    }

    /**
     * 删除
     *
     * @param idList 主键列表
     */
    @Override
    public void delete(List<String> idList) {
        if(CollUtil.isEmpty(idList)) {
            return;
        }
        IdsQueryWrapperBuilder<RegisterInfo> idQueryWrapperBuilder = new IdsQueryWrapperBuilder<>(RegisterInfo.class, idList);
        List<RegisterInfo> list = this.indexHelper.searchByIds(idQueryWrapperBuilder.build());
        boolean flag = list.stream().anyMatch(a->!RegisterExecuteStatusEnum.DOWN_LINE.getCode().equals(a.getExecuteStatus()));
        if(flag) {
            throw new AppException(JdfSystemMsgEnum.JUST_DELETE_REGISTER_DOWN_LINE);
        }
        DeleteByIdsWrapperBuilder<RegisterInfo> deleteByIdsWrapperBuilder = new DeleteByIdsWrapperBuilder<>(RegisterInfo.class, idList);
        this.indexHelper.deleteByIds(deleteByIdsWrapperBuilder.build());
        this.sync();
    }

    private QueryWrapperBuilder<RegisterInfo> buildQuery(RegisterInfo registerInfo) {
        QueryWrapperBuilder<RegisterInfo> queryWrapperBuilder = new QueryWrapperBuilder<>(RegisterInfo.class);
        if (CharSequenceUtil.isNotEmpty(registerInfo.getWorkspaceId())) {
            queryWrapperBuilder.matchStr(RegisterInfo::getWorkspaceId, registerInfo.getWorkspaceId(), MatchTypeEnum.TERM, BooleanClause.Occur.MUST);
        }
        if (CharSequenceUtil.isNotEmpty(registerInfo.getNodeName())) {
            queryWrapperBuilder.matchStr(RegisterInfo::getNodeName, registerInfo.getNodeName(), MatchTypeEnum.ALL_LIKE, BooleanClause.Occur.MUST);
        }
        if (CharSequenceUtil.isNotEmpty(registerInfo.getIp())) {
            queryWrapperBuilder.matchStr(RegisterInfo::getIp, registerInfo.getIp(), MatchTypeEnum.PREFIX, BooleanClause.Occur.MUST);
        }
        return queryWrapperBuilder;
    }

    /**
     * 初始化
     */
    @Override
    public void init() {
        String bindIp = this.configInfoCache.getValue(ConfigCodeEnum.BIND_IP.getCode());
        String workspaceId = this.configInfoCache.getValue(ConfigCodeEnum.WORKSPACE_ID.getCode());
        String nodeName = this.configInfoCache.getValue(ConfigCodeEnum.NODE_NAME.getCode());
        QueryWrapperBuilder<RegisterInfo> queryWrapperBuilder = new QueryWrapperBuilder<>(RegisterInfo.class);
        queryWrapperBuilder.matchStr(RegisterInfo::getIp, bindIp, MatchTypeEnum.TERM, BooleanClause.Occur.MUST);
        List<RegisterInfo> list = this.indexHelper.search(queryWrapperBuilder.build());
        if (CollUtil.size(list) > 1) {
            log.warn("found multiple registration information");
            RegisterInfo registerInfo = list.get(0);
            List<String> delIds = list.stream()
                    .map(RegisterInfo::getId).filter(f -> !registerInfo.getId().equals(f)).collect(Collectors.toList());
            DeleteByIdsWrapperBuilder<RegisterInfo> deleteByIdsWrapperBuilder = new DeleteByIdsWrapperBuilder<>(RegisterInfo.class, delIds);
            this.indexHelper.deleteByIds(deleteByIdsWrapperBuilder.build());
            list = this.indexHelper.search(queryWrapperBuilder.build());
        }
        RegisterExecuteStatusEnum statusEnum = RegisterExecuteStatusEnum.NORMAL;
        if (CollUtil.isEmpty(list)) {
            RegisterInfo registerInfo = new RegisterInfo();
            registerInfo.setWorkspaceId(workspaceId);
            registerInfo.setNodeName(nodeName);
            registerInfo.setIp(bindIp);
            registerInfo.setExecuteStatus(statusEnum.getCode());
            registerInfo.setAttachInfo(CollUtil.newHashSet(StrConstant.NOT_SYNC));
            this.indexHelper.addDocument(registerInfo);
        } else {
            RegisterInfo registerInfo = list.get(0);
            registerInfo.setWorkspaceId(workspaceId);
            registerInfo.setNodeName(nodeName);
            registerInfo.setExecuteStatus(statusEnum.getCode());
            registerInfo.setAttachInfo(CollUtil.newHashSet(StrConstant.NOT_SYNC));
            this.indexHelper.updateDocumentById(registerInfo);
        }
        this.sync();
        log.info("完成节点:{}, IP:{} 注册信息初始化", nodeName, bindIp);
    }

    private void sync() {
        QueryWrapperBuilder<RegisterInfo> queryWrapperBuilder = new QueryWrapperBuilder<>(RegisterInfo.class);
        List<RegisterInfo> list = this.indexHelper.search(queryWrapperBuilder.build());
        List<String> ipList = list.stream().map(RegisterInfo::getIp).collect(Collectors.toList());
        this.ipCache.addAllIp(ipList);
    }
}
